﻿using Cofe.Core.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cofe.Core.Validater
{
    public enum ActionType
    {
        /// <summary>
        /// Return the result directly, PropertyType = Func&lt;IParameterDictionary, ot&gt; or Action&lt;IParameterDictionary&gt;
        /// </summary>
        Sync,
        /// <summary>
        /// Result a Task so the result can return asynchronously, PropertyType = Func&lt;IParameterDictionary, Task&lt;ot&gt;&gt; or Func&lt;IParameterDictionary, Task&gt;
        /// </summary>
        Async
    }

    public class ActionAttribute : PropertyTypeAttribute
    {
        private static Type constructActionType(ActionType at, Type ot)
        {
            Type generic = typeof(Task<>);
            Type func = typeof(Func<,>);
            if (at == ActionType.Sync)
                return func.MakeGenericType(typeof(ParameterDic), ot);
            return func.MakeGenericType(typeof(ParameterDic), generic.MakeGenericType(ot)); //Func<IParameterDictionary, Task>>
        }

        private static Type constructActionType(ActionType at)
        {
            if (at == ActionType.Sync)
                return typeof(Action<ParameterDic>);
            return typeof(Func<ParameterDic, Task>);
        }

        /// <summary>
        /// Async : Func&lt;IParameterDictionary, Task&lt;ot&gt;&gt;
        /// Sync  : Func&lt;IParameterDictionary, ot&gt;
        /// </summary>
        /// <param name="at"></param>
        /// <param name="outputType"></param>
        public ActionAttribute(ActionType at, Type outputType, params string[] parameters)
            : base(constructActionType(at, outputType))
        {
            ActionType = at;
            Parameters = parameters;
            OutputType = outputType;
            ItemType = null;
        }

        /// <summary>
        /// Async : Func&lt;IParameterDictionary, Task&gt;
        /// Sync  : Func&lt;IParameterDictionary, ot&gt;
        /// </summary>
        /// <param name="at"></param>
        public ActionAttribute(ActionType at, params string[] parameters)
            : base(constructActionType(at))
        {
            ActionType = at;
            Parameters = parameters;
            OutputType = null;
            ItemType = null;
        }

        public string[] Parameters { get; protected set; }
        public ActionType ActionType { get; protected set; }

        /// <summary>
        /// The property type of output, for list, it's an generic IEnumerable.
        /// </summary>
        public Type OutputType { get; protected set; }

        /// <summary>
        /// Type if the item in list if proprty type is list.
        /// </summary>
        public Type ItemType { get; protected set; }
    }
}
